<?php
/**
 * Description of RbacEx
 *
 * @author mz
 */
class RbacEx {
	private $bit;
	private $bizRule;
	private $userPermissions;
	private $applyType;
	
    public function init() {  }

	private function getUserPermissions($uid = null) {
        if ($uid) {
			$sql = "SELECT (SELECT `permissions` FROM `users` WHERE `id`=$uid) + 0";
        }
		else {
			if (Yii::app()->user->isGuest)
				$sql = "SELECT (SELECT `base_permissions` FROM `roles` WHERE `name`='guest') + 0";
			else
				$sql = 'SELECT (SELECT `permissions` FROM `users` WHERE `id`='.Yii::app()->user->id.') + 0';
		}
        $command = Yii::app()->db->createCommand($sql);
        $this->userPermissions = 0 + $command->queryScalar();

	}

	private function getPermissionProperties($controller, $action) {
		$sql = 'SELECT * FROM `permissions` WHERE `controller`=:controller AND `action`=:action LIMIT 1';
        $command = Yii::app()->db->createCommand($sql);

		$command->bindParam(":controller", $controller, PDO::PARAM_STR);
        $command->bindParam(":action", $action, PDO::PARAM_STR);

		$result = $command->query();
		
		foreach($result as $r) {
			$this->bit = $r['id'] ? 0 + $r['id'] : -1;
			$this->bizRule = $r['biz_rule'];
			$this->applyType = $r['biz_rule_apply'];
			break;
		}
		
	}

    public function checkAccess($controller, $action, $uid = null, array $fakeGET = null)
    {
		if ($controller == null || $controller == '') $controller = Yii::app()->defaultController;
		
		$this->getUserPermissions($uid);
		$this->getPermissionProperties($controller, $action);

        if($fakeGET != null){ // lets fake GET request params for evaluating business rule
            $save_GET = $_GET;
            $_GET = $fakeGET;
        }
		
		$bit_granted = $this->bit && ($this->userPermissions & (1 << $this->bit));

		$allow = false;
		$branch = 0;

		if (empty($this->bizRule) || $this->bizRule == null)
			$allow = $bit_granted;
		else {
			switch ($this->applyType) {
				case 'AND':
					if ($bit_granted && @eval($this->bizRule)) {
						$allow = true;
						$branch = 'AND (allowed)';
					}
					else {
						$branch = 'AND (refused)';
					}
					break;
				case 'OR';
					if ($bit_granted || @eval($this->bizRule)) {
						$allow = true;
						$branch = 'OR (allowed)';
					} else {
						$branch = 'OR (refused)';
					}
					break;
				case 'BIZRULE_ONLY':
					if (@eval($this->bizRule)) {
						$allow = true;
						$branch = 'BIZRULE_ONLY (allowed)';
					}
					else {
						$branch = 'BIZRULE_ONLY (refused)';
					}
					break;
				default:
					throw new CHttpException(500, 'Unhandled bizRule apply type. Engine error!');
			}

		}
//		DEBUG:
//		if (!$allow) {
//			echo '<pre>';
//			echo "controller/action = ",$controller,"/", $action,"\n";
//			echo "bit_granted = ",$bit_granted,"\n";
//			echo "\$this->bit = ",$this->bit,"\n";
//			echo "\$this->bizRule = ",var_dump($this->bizRule);
//			echo "permissionMask  = 0x",str_pad(dechex($this->bit > 0 ? 1 << $this->bit : 0), 16, '0', STR_PAD_LEFT),"\n";
//			echo "userPermissions = 0x", str_pad(dechex($this->userPermissions), 16, '0', STR_PAD_LEFT),"\n";
//			echo "\$this->applyType = ",$this->applyType,"\n";
//			echo "branch = ",$branch,"\n";
//			echo '</pre>';
//			//die();
//		}
        if($fakeGET != null){ // restore original _GET
            $_GET = $save_GET;
        }

        return $allow;
    }

}
?>
